package com.tdam2011.grupo02.data;

import java.sql.Date;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.Iterator;

import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.CallLog;
import android.provider.ContactsContract;
import android.text.format.DateFormat;
import android.util.Log;

import com.tdam2011.grupo02.data.sort.*;
import com.tdam2011.grupo02.domain.FilterInterface;
import com.tdam2011.grupo02.domain.Llamada;
import com.tdam2011.grupo02.domain.Mail;
import com.tdam2011.grupo02.domain.MensajeWeb;
import com.tdam2011.grupo02.domain.SMS;
import com.tdam2011.grupo02.ui.ContactsManagerSingleton;

public class LogsController {

	private Context context;
	private LinkedList<SMS> smsData;
	private ContactDroidSettings settings;

	public final static String CONTACTS_ALL = "-1";
	public final static int CALL_TYPE_ALL = 0;

	public LogsController(Context context) {
		this.context = context;
		settings = new ContactDroidSettings(context);
	}

	/**
	 * Elimina el registro de acciones realizadas por el usuario: llamadas
	 * enviadas y recibidas, sms enviados y recibidos, mails enviados y mensajes
	 * web enviados.
	 */
	public void deleteAll() {
		DatabaseHelperSingleton.getInstance(context).getDatabaseHelper()
				.deleteAllLogs();
		deleteAllCallLog();
		deleteAllSmsLog();
	}

	/***************************** CALLS LOG *****************************/

	private Cursor getCallLog(String id, String name) {
		String[] strFields = { CallLog.Calls._ID, CallLog.Calls.NUMBER,
				CallLog.Calls.TYPE, CallLog.Calls.CACHED_NAME,
				CallLog.Calls.CACHED_NUMBER_TYPE, CallLog.Calls.DATE,
				CallLog.Calls.DURATION, CallLog.Calls.TYPE };
		String strOrder = CallLog.Calls.DATE + " DESC";
		String clause = null;
		String[] params = null;

		if (id != CONTACTS_ALL) {
			clause = CallLog.Calls.CACHED_NAME + " = ?";
			params = new String[] { name };
		}

		Cursor mCallCursor = context.getContentResolver().query(
				CallLog.Calls.CONTENT_URI, strFields, clause, params, strOrder);

		return mCallCursor;
	}

	public LinkedList<Llamada> getCalls(String id, String name) {
		Cursor calls = getCallLog(id, name);
		Llamada info = null;
		LinkedList<Llamada> callData = new LinkedList<Llamada>();
		Uri imgUri = null;
		String nombre = "";

		while (calls.moveToNext()) {
			info = new Llamada();

			info.set_ID(calls.getInt(calls.getColumnIndex(CallLog.Calls._ID)));
			nombre = calls.getString(calls
					.getColumnIndex(CallLog.Calls.CACHED_NAME));
			if (nombre == null || nombre.trim().equals(""))
				nombre = "Unknow";
			info.setNombre(nombre);
			imgUri = ContactsManagerSingleton.getInstance(context)
					.getContactsManager().getImageUriByContact(nombre);
			info.setImagen(imgUri);
			info.setNumero(calls.getString(calls
					.getColumnIndex(CallLog.Calls.NUMBER)));
			info.setFecha((new Date(calls.getLong(calls
					.getColumnIndex(CallLog.Calls.DATE)))));
			info.setDuracion(calls.getLong(calls
					.getColumnIndex(CallLog.Calls.DURATION)) + " segundos");
			info.setTipoNumero(calls.getInt(calls
					.getColumnIndex(CallLog.Calls.CACHED_NUMBER_TYPE)));
			info.setTipoLlamada(calls.getInt(calls
					.getColumnIndex(CallLog.Calls.TYPE)));

			callData.add(info);
		}

		calls.close();

		applyOrderParameters(callData);
		applyFilters(callData);
		applyFilterCurrentDate(callData);

		return callData;
	}

	public int deleteCallLogItem(Llamada call) {
		Log.d("DEMO", "llamada id = " + call.get_ID());
		String where = CallLog.Calls._ID + " = ? ";
		String[] selectionArgs = new String[] { String.valueOf(call.get_ID()) };

		return context.getContentResolver().delete(CallLog.Calls.CONTENT_URI,
				where, selectionArgs);
	}

	public void deleteAllCallLog() {
		context.getContentResolver().delete(CallLog.Calls.CONTENT_URI, null,
				null);
	}

	/***************************** SMS LOG *****************************/

	public LinkedList<SMS> getFirstSMSConversations(String name) {
		if (name == null) {
			return loadFirstSMSConversations();
		} else {
			return loadFirstSMSConversations(name);
		}
	}

	private LinkedList<SMS> loadFirstSMSConversations(String name) {
		loadConversationsSms();
		Cursor cur = getSMSs();

		LinkedList<SMS> smsList = new LinkedList<SMS>();
		SMS sms = null;
		String nombre = null;

		Iterator<SMS> threads = smsData.iterator();
		while (threads.hasNext()) {
			sms = threads.next();
			cur.moveToFirst();

			do {
				if (sms.getThreadId().equals(
						cur.getString(cur.getColumnIndex("thread_id")))) {

					nombre = this.getConversationNameByNumber(cur.getString(cur
							.getColumnIndex("address")));

					if (name.equals(nombre)) {
						Date date = new Date(cur.getLong(cur
								.getColumnIndex("date")));
						sms.setNombre(nombre);
						sms.setImageUri(ContactsManagerSingleton
								.getInstance(context).getContactsManager()
								.getImageUriByContact(nombre));
						sms.setNumero(cur.getString(cur
								.getColumnIndex("address")));
						sms.setFecha(date);

						smsList.add(sms);
					}
					break;
				}
			} while (cur.moveToNext());
		}

		applyOrderParameters(smsList);
		// applyFilterCurrentDate(smsList);

		return smsList;
	}

	private LinkedList<SMS> loadFirstSMSConversations() {
		loadConversationsSms();
		Cursor cur = getSMSs();
		SMS sms = null;
		String nombre = null;

		Iterator<SMS> threads = smsData.iterator();
		while (threads.hasNext()) {
			sms = threads.next();
			cur.moveToFirst();

			do {
				if (sms.getThreadId().equals(
						cur.getString(cur.getColumnIndex("thread_id")))) {

					nombre = this.getConversationNameByNumber(cur.getString(cur
							.getColumnIndex("address")));

					Date date = new Date(
							cur.getLong(cur.getColumnIndex("date")));
					sms.setNombre(nombre);
					sms.setImageUri(ContactsManagerSingleton
							.getInstance(context).getContactsManager()
							.getImageUriByContact(nombre));
					sms.setNumero(cur.getString(cur.getColumnIndex("address")));
					sms.setFecha(date);

					break;
				}
			} while (cur.moveToNext());
		}

		applyOrderParameters(smsData);
		applyFilterCurrentDate(smsData);

		return smsData;
	}

	private void loadConversationsSms() {
		Uri smsURI = Uri.parse("content://sms/conversations");

		Cursor cur = context.getContentResolver().query(smsURI, null, null,
				null, null);

		smsData = new LinkedList<SMS>();
		SMS sms = null;

		while (cur.moveToNext()) {
			sms = new SMS();
			sms.setThreadId(cur.getString(0));
			sms.setMensaje(cur.getString(2));
			smsData.add(sms);
		}
	}

	private Cursor getSMSs() {
		Uri smsURI = Uri.parse("content://sms/");
		String columns[] = new String[] { "address", "date", "thread_id" };
		// type 1 = otro contacto, type 2 = usuario /
		// address, body
		Cursor cur = context.getContentResolver().query(smsURI, columns, null,
				null, "date desc");

		return cur;

	}

	public LinkedList<SMS> loadConversationSms(String threadId) {
		Uri smsURI = Uri.parse("content://sms/");
		String columns[] = new String[] { "address", "body", "date",
				"thread_id", "type" }; // type 1 = otro contacto, type 2 =
										// usuario
		String clause = "thread_id = ?";
		String selection[] = new String[] { threadId };

		Cursor cur = ((Activity) context).managedQuery(smsURI, columns, clause,
				selection, "date asc");

		smsData = new LinkedList<SMS>();
		SMS sms = null;

		while (cur.moveToNext()) {
			sms = new SMS();
			sms.setThreadId(threadId);
			Date date = new Date(cur.getLong(cur.getColumnIndex("date")));
			sms.setNumero(cur.getString(cur.getColumnIndex("address")));
			sms.setMensaje(cur.getString(cur.getColumnIndex("body")));
			sms.setFecha(date);
			sms.setType(Integer.parseInt(cur.getString(cur
					.getColumnIndex("type"))));

			smsData.add(sms);
		}

		cur.close();

		applyFilters(smsData);
		applyFilterCurrentDate(smsData);

		return smsData;
	}

	private String getConversationNameByNumber(String num) {
		String name = "";
		String id = " ";

		Cursor cur = context.getContentResolver().query(
				ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
				ContactsContract.CommonDataKinds.Phone.NUMBER + " = ?",
				new String[] { num }, null);

		// recuperar id de contacto del telefono ingresado por parametro

		if (cur.moveToNext()) {
			id = cur.getString(cur
					.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID));
		}

		name = ContactsManagerSingleton.getInstance(context)
				.getContactsManager().getContactNameById(id);

		if (name == null || name.trim().compareTo(" ") == 0)
			name = num;

		return name;
	}

	public int deleteSmsLog(SMS sms) {
		Uri smsURI = Uri.parse("content://sms");
		String where = "thread_id = ? and date = ? and address = ? and body = ?";
		String selectionArgs[] = new String[] { sms.getThreadId(),
				String.valueOf(sms.getFecha().getTime()), sms.getNumero(),
				sms.getMensaje() };

		return context.getContentResolver()
				.delete(smsURI, where, selectionArgs);
	}

	public int deleteSmsConversationLog(String threadId) {
		Uri smsURI = Uri.parse("content://sms");
		String where = "thread_id = ?";
		String selectionArgs[] = new String[] { threadId };

		return context.getContentResolver()
				.delete(smsURI, where, selectionArgs);
	}

	public int deleteSmsConversationLog(LinkedList<String> threadId) {
		int num = 0;
		for (String aux : threadId)
			num += deleteSmsConversationLog(aux);

		return num;
	}

	public void deleteAllSmsLog() {
		Uri smsURI = Uri.parse("content://sms");
		context.getContentResolver().delete(smsURI, null, null);
	}

	/***************************** WEB MESSAGES LOG *****************************/

	public LinkedList<MensajeWeb> getWebMessagesByContact(String nombreContacto) {
		LinkedList<MensajeWeb> msgws = DatabaseHelperSingleton
				.getInstance(context).getDatabaseHelper()
				.getMsgwByContact(nombreContacto);

		applyOrderParameters(msgws);
		applyFilterCurrentDate(msgws);

		return msgws;
	}

	public LinkedList<MensajeWeb> getWebMessagesConversation(
			String nombreContacto) {
		LinkedList<MensajeWeb> msgws = DatabaseHelperSingleton
				.getInstance(context).getDatabaseHelper()
				.getMsgwConversation(nombreContacto);

		applyFilters(msgws);

		return msgws;
	}

	public LinkedList<MensajeWeb> getWebMessagesOutboxByContact(
			String nombreContacto) {
		LinkedList<MensajeWeb> msgws = DatabaseHelperSingleton
				.getInstance(context).getDatabaseHelper()
				.getMsgwOutboxByContact(nombreContacto);

		applyOrderParameters(msgws);
		applyFilterCurrentDate(msgws);

		return msgws;
	}

	public int deleteWebMessagesConversation(MensajeWeb msgw) {
		return DatabaseHelperSingleton.getInstance(context).getDatabaseHelper()
				.deleteMsgwConversation(msgw);
	}

	/***************************** MAILS LOG *****************************/

	public LinkedList<Mail> getAllMails(String nombreContacto) {
		LinkedList<Mail> mails = DatabaseHelperSingleton.getInstance(context)
				.getDatabaseHelper().getAllMailsInfo(nombreContacto);

		applyOrderParameters(mails);
		applyFilterCurrentDate(mails);

		return mails;
	}

	/***************************** ORDER AND FILTERS *****************************/

	/**
	 * Aplica parametros de ordenamiento en base a las preferences
	 * 
	 * @param callsToFilter
	 */
	private <T> void applyOrderParameters(LinkedList<T> callsToFilter) {
		if (callsToFilter != null && !callsToFilter.isEmpty()) {

			String order = settings.getOrder((FilterInterface) callsToFilter
					.get(0));
			String orderType = settings
					.getOrderType((FilterInterface) callsToFilter.get(0));
			Comparator<T> comparator = null;

			if (order.equals(ContactDroidSettings.ORDER_DATE)) {
				if (orderType.equals(ContactDroidSettings.ORDER_TYPE_ASC)) {
					comparator = (Comparator<T>) new SortDateAsc();
				} else {
					comparator = (Comparator<T>) new SortDateDesc();
				}
			} else {
				if (orderType.equals(ContactDroidSettings.ORDER_TYPE_ASC)) {
					comparator = (Comparator<T>) new SortContactAsc();
				} else {
					comparator = (Comparator<T>) new SortContactDesc();
				}
			}

			Collections.sort(callsToFilter, comparator);
		}
	}

	/**
	 * Aplica filtros en base a las preferences
	 * 
	 * @param dataToFilter
	 */
	private <T> void applyFilters(LinkedList<T> dataToFilter) {
		if (dataToFilter != null && !dataToFilter.isEmpty()) {
			String filterString = settings
					.getFilter((FilterInterface) dataToFilter.get(0));
			int filter;

			if (!filterString.equals(ContactDroidSettings.FILTER_ALL)) {
				filter = Integer.parseInt(filterString);

				Iterator<FilterInterface> iterator = (Iterator<FilterInterface>) dataToFilter
						.iterator();
				FilterInterface aux;

				while (iterator.hasNext()) {
					aux = iterator.next();

					if (aux.getFilter() != filter)
						iterator.remove();
				}
			}
		}
	}

	/**
	 * Filtra el set de datos por fecha actual
	 * 
	 * @param dataToFilter
	 */
	private <T> void applyFilterCurrentDate(LinkedList<T> dataToFilter) {
		if (dataToFilter != null && !dataToFilter.isEmpty()) {
			if (settings.isFilterCurrentDate((FilterInterface) dataToFilter
					.get(0))) {
				Date currentDate = new Date(Calendar.getInstance()
						.getTimeInMillis());
				String dateAct = DateFormat.getDateFormat(context).format(
						currentDate);

				Iterator<T> iterator = dataToFilter.iterator();
				FilterInterface aux;

				while (iterator.hasNext()) {
					aux = (FilterInterface) iterator.next();
					String fechaMsj = DateFormat.getDateFormat(context).format(
							aux.getFilterDateValue());

					if (!fechaMsj.equals(dateAct)) {
						iterator.remove();
					}
				}
			}
		}
	}

}
